#ifndef __CMATRIX2D_H__
#define __CMATRIX2D_H__

#include "StdDefs.h"
#include "CMathFixed.h"
#include "CVector2d.h"



// CMatrix2d* must maintain casting ability with (fixed*).
// CMatrix2d may not have virtuals, inherited, or instantiated data.
 


class CMatrix2d
{
public:
	CMatrix2d();
	CMatrix2d( const fixed* m );
	CMatrix2d( fixed m00, fixed m01, fixed m10, fixed m11,
			   int16 nOfArthmeticOpsTriggeringOrientationFixup = 0 );
	CMatrix2d( const CVector2d* col, 
			   int16 nOfArthmeticOpsTriggeringOrientationFixup = 0 );
	CMatrix2d( const CVector2d& col0, const CVector2d& col1,
			   int16 nOfArthmeticOpsTriggeringOrientationFixup = 0 ); 
	CMatrix2d( const CMatrix2d& m );
	~CMatrix2d(){}

	CMatrix2d&			Clear();
	CMatrix2d&			LoadIdentity();
	CMatrix2d&			Orthonormalize();
	CMatrix2d&			Scale( fixed si, fixed sj );
	CMatrix2d&			Scale( const CVector2d& s );
	CMatrix2d&			Rotate( fixed degrees );

	CMatrix2d&			operator=( const fixed* m ); 
	CMatrix2d&			operator=( const CVector2d* col );

	CMatrix2d&			operator*=( const CMatrix2d& b );
	//CMatrix2d&		operator+=( const 

	fixed&				operator[]( int idx );
	fixed const&		operator[]( int idx ) const;

	friend CMatrix2d	operator*( const CMatrix2d& a, const CMatrix2d& b );

	int16				GetNumOfArithmeticOpsSinceLastFixup() const;
	void				SetNumOfArithmeticOpsTriggeringOrientationFixup( int16 val );
	int16				GetNumOfArithmeticOpsTriggeringOrientationFixup() const;

	CVector2d			m_col0;
	CVector2d			m_col1;

protected:
	void				IncrementOperationCount();
	void				ConsiderOrientationFixup();

	boolean				m_orientationFixupIsApplicable;
	uint8				m_reserved[3];
	uint16				m_nOfArithmeticOpsSinceLastFixup;
	uint16				m_nOfArthmeticOpsTriggeringOrientationFixup;
};




inline
CMatrix2d::CMatrix2d( const CMatrix2d& m )
{
	*this = m;
}


inline
CMatrix2d& CMatrix2d::operator=( const fixed* m )
{ 
	ASSERT( m ); 

	MEMCPY( this, m, sizeof( CMatrix2d ) );

	ASSERT( !m_orientationFixupIsApplicable || 
			( m_orientationFixupIsApplicable && m_nOfArthmeticOpsTriggeringOrientationFixup ) );

	return *this;
}


inline
CMatrix2d& CMatrix2d::operator=( const CVector2d* col )
{ 
	m_col0 = *col; 
	m_col1 = *( col + 1 ); 

	m_nOfArithmeticOpsSinceLastFixup = 0;

	return *this;
}


inline
fixed& CMatrix2d::operator[]( int idx )
{
	ASSERT( idx < 4 );

	return *( ( (fixed*)this ) + idx );
}


inline
fixed const& CMatrix2d::operator[]( int idx ) const
{
	ASSERT( idx < 4 );

	return *( ( (fixed*)this ) + idx );
}


inline
int16 CMatrix2d::GetNumOfArithmeticOpsSinceLastFixup() const
{
	return m_nOfArithmeticOpsSinceLastFixup;
}


inline
void CMatrix2d::SetNumOfArithmeticOpsTriggeringOrientationFixup( int16 val )
{
	m_nOfArthmeticOpsTriggeringOrientationFixup = val;

	if( m_nOfArthmeticOpsTriggeringOrientationFixup )
		m_orientationFixupIsApplicable = TRUE;
	else
		m_orientationFixupIsApplicable = FALSE;
}


inline
int16 CMatrix2d::GetNumOfArithmeticOpsTriggeringOrientationFixup() const
{
	return m_nOfArthmeticOpsTriggeringOrientationFixup;
}





#endif // __CMATRIX2D_H__